﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using NHibernate;
using NHibernate.Criterion;
using System.Data;
using System.Collections;

namespace NHibernateBusiness.Data
{
    internal class NHibernateHelper : INHibernateHelper
    {
        private ISession _session;


        public NHibernateHelper()
        {
            try
            {
                _session = Common.ISessionDataFactory.GetSession();
            }
            catch (Exception e)
            {
                throw new Exception(e.Message);
            }
        }


        public T GetQueryById<T>(string id)
        {
            try
            {
                return _session.Get<T>(id);
            }
            catch (Exception e)
            {
                throw new Exception(e.Message);
            }
        }

        public IList<T> GetQuery<T>()
        {
            try
            {
                return _session.CreateCriteria(typeof(T))
                    .List<T>();
            }
            catch (Exception e)
            {
                throw new Exception(e.Message);
            }
        }


        public IList<T> GetQuery<T>(T t)
        {
            try
            {
                Example exa = Example.Create(t)
                    .IgnoreCase();
                IList<T> list = _session.CreateCriteria(typeof(T))
                    .Add(exa)
                    .List<T>();
                return list;
            }
            catch (Exception e)
            {
                throw new Exception(e.Message);
            }
        }

        public IList<T> GetQuery<T>(T t, string order, bool isAsc)
        {
            try
            {
                Example exa = Example.Create(t)
                   .IgnoreCase();
                IList<T> list = _session.CreateCriteria(typeof(T))
                  .Add(exa)
                  .AddOrder(new Order(order, isAsc))
                  .List<T>();
                return list;
            }
            catch (Exception e)
            {
                throw new Exception(e.Message);
            }
        }

        public IList<T> GetQueryBySql<T>(string sqlText)
        {
            try
            {
                IList<T> list = _session.CreateQuery(sqlText)
                    .List<T>();
                return list;
            }
            catch (Exception e)
            {
                throw new Exception(e.Message);
            }
        }

        public IList<T> GetQuery<T>(string name, string value)
        {
            try
            {
                return _session.CreateCriteria(typeof(T))
                    .Add(Restrictions.Eq(name, value))
                    .List<T>();
            }
            catch (Exception e)
            {
                throw new Exception(e.Message);
            }
        }

        public IList<T> GetQuery<T>(string name, string value, string tName, string tValue)
        {
            try
            {
                return _session.CreateCriteria(typeof(T))
                    .Add(Restrictions.Eq(name, value))
                    .Add(Restrictions.Eq(tName, tValue))
                    .List<T>();
            }
            catch (Exception e)
            {
                throw new Exception(e.Message);
            }
        }

        public void Save(object obj)
        {
            try
            {
                _session.Merge(obj);
                _session.Flush();
            }
            catch (Exception e)
            {
                throw new Exception(e.Message);
            }
        }

        public void Save(string sql)
        {
            try
            {
                _session.CreateQuery(sql);
                _session.Flush();
            }
            catch (Exception e)
            {
                throw new Exception(e.Message);
            }
        }

        public void SaveOrUpdate(object obj)
        {
            try
            {
                _session.Merge(obj);
                _session.SaveOrUpdate(obj);
                _session.Flush();
            }
            catch (Exception e)
            {
                throw new Exception(e.Message);
            }
        }

        public void Update(object obj)
        {
            try
            {
                _session.Merge(obj);
                _session.Flush();
            }
            catch (Exception e)
            {
                throw new Exception(e.Message);
            }
        }

        public void Update(string sql)
        {
            try
            {
                _session.CreateQuery(sql);
                _session.Flush();
            }
            catch (Exception e)
            {
                throw new Exception(e.Message);
            }
        }

        public void Delete<T>(T t)
        {
            try
            {
                _session.Clear();
                _session.Delete(t);
                _session.Flush();
            }
            catch (Exception e)
            {
                throw new Exception(e.Message);
            }
        }

        public int Delete(string sqlText)
        {
            try
            {
                int result = _session.Delete(sqlText);
                _session.Flush();
                return result;
            }
            catch (Exception e)
            {
                throw new Exception(e.Message);
            }
        }

        public IList DoSql(string sql)
        {
            try
            {
                return _session.CreateSQLQuery(sql).List();
            }
            catch (Exception e)
            {
                throw new Exception(e.Message);
            }
        }

        public DataSet GetQueryForDs<T>()
        {
            return ConvertToDataSet<T>(GetQuery<T>());
        }

        public DataSet DoSqlForDs(string sql)
        {
            return ListToDataSet(DoSql(sql));
        }

        public DataSet GetQueryForDs<T>(T t)
        {
            return ConvertToDataSet<T>(GetQuery<T>(t));
        }

        public DataSet GetQueryForDs<T>(T t, string order, bool isAsc)
        {
            return ConvertToDataSet<T>(GetQuery<T>(t, order, isAsc));
        }

        public DataSet GetQueryBySqlForDs<T>(string sqlText)
        {
            return ConvertToDataSet<T>(GetQueryBySql<T>(sqlText));
        }

        public DataSet GetQueryForDs<T>(string name, string value)
        {
            return ConvertToDataSet<T>(GetQuery<T>(name, value));
        }

        public DataSet GetQueryForDs<T>(string name, string value, string tName, string tValue)
        {
            return ConvertToDataSet<T>(GetQuery<T>(name, value, tName, tValue));
        }


        private DataSet ConvertToDataSet<T>(IList<T> list)
        {
            try
            {
                if (list == null || list.Count < 1)
                {
                    return null;
                }
                DataSet ds = new DataSet();
                DataTable dt = new DataTable();
                System.Reflection.PropertyInfo[] myPropertyInfo = typeof(T).GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);

                foreach (System.Reflection.PropertyInfo pi in myPropertyInfo)
                {
                    Type type = pi.PropertyType;
                    if (type == typeof(int?))
                    {
                        type = typeof(int);
                    }
                    if (type == typeof(DateTime?))
                    {
                        type = typeof(DateTime);
                    }
                    dt.Columns.Add(pi.Name, type);
                }


                foreach (T t in list)
                {
                    if (t == null)
                    {
                        continue;
                    }

                    DataRow row = dt.NewRow();
                    foreach (System.Reflection.PropertyInfo pi in myPropertyInfo)
                    {
                        object obj = pi.GetValue(t, null);
                        if (obj != null)
                        {
                            row[pi.Name] = obj;
                        }
                    }
                    dt.Rows.Add(row);
                }

                ds.Tables.Add(dt);
                return ds;
            }
            catch (Exception e)
            {
                throw new Exception(e.Message);
            }
        }
        private DataSet ListToDataSet(IList list)
        {
            try
            {
                DataSet ds = new DataSet();
                DataTable dt = new DataTable();

                System.Reflection.PropertyInfo[] p = list[0].GetType().GetProperties();
                foreach (System.Reflection.PropertyInfo pi in p)
                {
                    Type type = pi.PropertyType;
                    if (type == typeof(int?))
                    {
                        type = typeof(int);
                    }
                    if (type == typeof(DateTime?))
                    {
                        type = typeof(DateTime);
                    }
                    dt.Columns.Add(pi.Name, type);
                }
                for (int i = 0; i < list.Count; i++)
                {
                    DataRow row = dt.NewRow();
                    foreach (System.Reflection.PropertyInfo pi in p)
                    {
                        object obj = pi.GetValue(list[i], null);
                        if (obj != null)
                        {
                            row[pi.Name] = obj;
                        }
                    }
                    dt.Rows.Add(row);
                }
                ds.Tables.Add(dt);
                return ds;
            }
            catch (Exception e)
            {
                throw new Exception(e.Message);
            }
        }
    }
}
